﻿using SqlSugar;
using System.Linq.Expressions;

namespace Luka;

/// <summary>
/// 基础仓储层
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class, new()
{
    #region 获取连接对象

    /// <summary>
    /// 连接对象
    /// </summary>
    private ISqlSugarClient Client { get; set; }

    /// <summary>
    /// 连接对象
    /// </summary>
    public ISqlSugarClient Session() => Client;

    /// <summary>
    /// 连接对象
    /// </summary>
    public ISugarQueryable<TEntity> Queryable() => Client.Queryable<TEntity>();

    /// <summary>
    /// 操作查询对象（多库）
    /// </summary>
    public ISugarQueryable<TEntity> QueryableAttr() => Client.AsTenant().QueryableWithAttr<TEntity>();

    /// <summary>
    /// 连接对象
    /// </summary>
    public IDeleteable<TEntity> Deleteable() => Client.Deleteable<TEntity>();

    /// <summary>
    /// 连接对象
    /// </summary>
    public IUpdateable<TEntity> Updateable() => Client.Updateable<TEntity>();

    /// <summary>
    /// 构造函数
    /// </summary>
    public BaseRepository()
    {
        var client = InternalApp.GetService<ISqlSugarClient>() ?? throw new NotImplementedException(nameof(ISqlSugarClient));
        if (typeof(TEntity).IsDefined(typeof(TenantAttribute), false))
        {
            Client = client.AsTenant().GetConnectionScopeWithAttr<TEntity>();
        }
        else
        {
            Client = client;
        }
    }

    #endregion 获取连接对象

    #region 普通操作方法

    #region 基本操作方法

    /// <summary>
    /// 根据主键判断是否存在
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public bool IsAny(object id) => Queryable().In(id).Any();

    /// <summary>
    /// 根据表达式判断是否存在
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public bool IsAny(Expression<Func<TEntity, bool>> expression) => Queryable().Any(expression);

    /// <summary>
    /// 根据主键查询单个
    /// </summary>
    /// <param name="id">主键id</param>
    /// <returns></returns>
    public TEntity GetSingle(object id) => Queryable().InSingle(id);

    /// <summary>
    /// 根据表达式查询单个
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public TEntity GetSingle(Expression<Func<TEntity, bool>> expression) => Queryable().Single(expression);

    /// <summary>
    /// 查询详情第一条
    /// </summary>
    /// <param name="expression">表达书树条件</param>
    /// <returns></returns>
    public TEntity GetFirst(Expression<Func<TEntity, bool>> expression) => Queryable().First(expression);

    /// <summary>
    /// 查询列表
    /// </summary>
    /// <returns></returns>
    public List<TEntity> GetList() => Queryable().ToList();

    /// <summary>
    /// 查询列表
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public List<TEntity> GetList(Expression<Func<TEntity, bool>> expression) => Queryable().Where(expression).ToList();

    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="input">公共分页参数</param>
    /// <returns></returns>
    public PagedOutput<TEntity> GetPagedList(PagedInput input)
    {
        int totalNumber = 0;
        int totalPage = 0;
        var data = Queryable().ToPageList(input.PageIndex, input.PageSize, ref totalNumber, ref totalPage);
        return new PagedOutput<TEntity> { TotalNumber = totalNumber, TotalPage = totalPage, Rows = data };
    }

    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="input">公共分页参数</param>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public PagedOutput<TEntity> GetPagedList(PagedInput input, Expression<Func<TEntity, bool>> expression)
    {
        int totalNumber = 0;
        int totalPage = 0;
        var data = Queryable().Where(expression).ToPageList(input.PageIndex, input.PageSize, ref totalNumber, ref totalPage);
        return new PagedOutput<TEntity> { TotalNumber = totalNumber, TotalPage = totalPage, Rows = data };
    }

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public int GetCount() => Queryable().Count();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public int GetCount(Expression<Func<TEntity, bool>> expression) => Queryable().Count(expression);

    /// <summary>
    /// 保存单个
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public int Save(TEntity model) => Client.Insertable(model).ExecuteCommand();

    /// <summary>
    /// 保存单个(返回主键id)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public int SaveRetundId(TEntity model) => Client.Insertable(model).ExecuteReturnIdentity();

    /// <summary>
    /// 保存单个(返回实体对象)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public TEntity SaveRetundEntity(TEntity model) => Client.Insertable(model).ExecuteReturnEntity();

    /// <summary>
    /// 保存单个（返回雪花id）
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public long SaveBySnowflakeId(TEntity model) => Client.Insertable(model).ExecuteReturnSnowflakeId();

    /// <summary>
    /// 保存集合（返回雪花id）
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public List<long> SaveAllBySnowflakeId(List<TEntity> models) => Client.Insertable(models).ExecuteReturnSnowflakeIdList();

    /// <summary>
    /// 保存集合
    /// </summary>
    /// <param name="input">输入值</param>
    /// <returns></returns>
    public int SaveAll(List<TEntity> models) => Client.Insertable(models).ExecuteCommand();

    /// <summary>
    /// 修改单个
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public int Update(TEntity model) => Client.Updateable(model).ExecuteCommand();

    /// <summary>
    /// 修改单个(添加条件)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public int Update(TEntity model, Expression<Func<TEntity, bool>> expression) => Client.Updateable(model).Where(expression).ExecuteCommand();

    /// <summary>
    /// 修改集合
    /// </summary>
    /// <param name="models">输入集合</param>
    /// <returns></returns>
    public int Update(List<TEntity> models) => Client.Updateable(models).ExecuteCommand();

    /// <summary>
    /// 修改集合(只更新某列)
    /// </summary>
    /// <param name="models">输入集合</param>
    /// <param name="columns"></param>
    /// <returns></returns>
    public int Update(List<TEntity> models, Expression<Func<TEntity, object>> columns) => Client.Updateable(models).UpdateColumns(columns).ExecuteCommand();

    /// <summary>
    /// 插入或更新集合
    /// </summary>
    /// <param name="models">输入值</param>
    /// <returns></returns>
    public int SaveOrUpdateAll(List<TEntity> models) => Client.Storageable(models).ExecuteCommand();

    /// <summary>
    /// 根据主键删除
    /// </summary>
    /// <param name="id">主键id</param>
    /// <returns></returns>
    public int UpdateIgnoreColumns(object id) => Deleteable().In(id).ExecuteCommand();

    /// <summary>
    /// 根据主键删除多个
    /// </summary>
    /// <param name="ids">id字符串，以逗号隔开</param>
    /// <returns></returns>
    public int Update(int[] ids) => Deleteable().In(ids).ExecuteCommand();

    /// <summary>
    /// 根据表达式删除
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public int Update(Expression<Func<TEntity, bool>> expression) => Deleteable().Where(expression).ExecuteCommand();

    #endregion 基本操作方法

    #region sql语句操作方法

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public TEntity GetSingleBySql(string sql) => Client.Ado.SqlQuerySingle<TEntity>(sql);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public TEntity GetSingleBySql(string sql, SugarParameter[] parameters) => Client.Ado.SqlQuerySingle<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public TEntity GetSingleBySql(string sql, List<SugarParameter> parameters) => Client.Ado.SqlQuerySingle<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public List<TEntity> GetListBySql(string sql) => Client.Ado.SqlQuery<TEntity>(sql);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public List<TEntity> GetListBySql(string sql, SugarParameter[] parameters) => Client.Ado.SqlQuery<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public List<TEntity> GetListBySql(string sql, List<SugarParameter> parameters) => Client.Ado.SqlQuery<TEntity>(sql, parameters);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public int ExecuteCommand(string sql) => Client.Ado.ExecuteCommand(sql);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public int ExecuteCommand(string sql, SugarParameter[] parameters) => Client.Ado.ExecuteCommand(sql, parameters);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public int ExecuteCommand(string sql, List<SugarParameter> parameters) => Client.Ado.ExecuteCommand(sql, parameters);

    /// <summary>
    /// 查询字符串
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public string GetStringBySql(string sql) => Client.Ado.GetString(sql);

    #endregion sql语句操作方法

    #endregion 普通操作方法

    #region 异步操作方法

    #region 基本操作方法

    /// <summary>
    /// 根据主键判断是否存在
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<bool> IsAnyAsync(object id) => await Queryable().In(id).AnyAsync();

    /// <summary>
    /// 根据表达式判断是否存在
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<bool> IsAnyAsync(Expression<Func<TEntity, bool>> expression) => await Queryable().AnyAsync(expression);

    /// <summary>
    /// 根据主键查询单个
    /// </summary>
    /// <param name="id">主键id</param>
    /// <returns></returns>
    public async Task<TEntity> GetSingleAsync(object id) => await Queryable().InSingleAsync(id);

    /// <summary>
    /// 根据表达式查询单个
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> expression) => await Queryable().SingleAsync(expression);

    /// <summary>
    /// 查询详情第一条
    /// </summary>
    /// <param name="expression">表达书树条件</param>
    /// <returns></returns>
    public async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> expression) => await Queryable().FirstAsync(expression);

    /// <summary>
    /// 查询列表
    /// </summary>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListAsync() => await Queryable().ToListAsync();

    /// <summary>
    /// 查询列表
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> expression) => await Queryable().Where(expression).ToListAsync();

    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="input">公共分页参数</param>
    /// <returns></returns>
    public async Task<PagedOutput<TEntity>> GetPagedListAsync(PagedInput input)
    {
        RefAsync<int> totalNumber = 0;
        RefAsync<int> totalPage = 0;
        var data = await Queryable().ToPageListAsync(input.PageIndex, input.PageSize, totalNumber, totalPage);
        return new PagedOutput<TEntity> { TotalNumber = totalNumber, TotalPage = totalPage, Rows = data };
    }

    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="input">公共分页参数</param>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<PagedOutput<TEntity>> GetPagedListAsync(PagedInput input, Expression<Func<TEntity, bool>> expression)
    {
        RefAsync<int> totalNumber = 0;
        RefAsync<int> totalPage = 0;
        var data = await Queryable().Where(expression).ToPageListAsync(input.PageIndex, input.PageSize, totalNumber, totalPage);
        return new PagedOutput<TEntity> { TotalNumber = totalNumber, TotalPage = totalPage, Rows = data };
    }

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public async Task<int> GetCountAsync() => await Queryable().CountAsync();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public async Task<int> GetCountAsync(Expression<Func<TEntity, bool>> expression) => await Queryable().CountAsync(expression);

    /// <summary>
    /// 保存单个
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<int> SaveAsync(TEntity model) => await Client.Insertable(model).ExecuteCommandAsync();

    /// <summary>
    /// 保存单个(返回主键id)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<int> SaveRetundIdAsync(TEntity model) => await Client.Insertable(model).ExecuteReturnIdentityAsync();

    /// <summary>
    /// 保存单个(返回实体对象)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<TEntity> SaveRetundEntityAsync(TEntity model) => await Client.Insertable(model).ExecuteReturnEntityAsync();

    /// <summary>
    /// 保存单个（返回雪花id）
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<long> SaveBySnowflakeIdAsync(TEntity model) => await Client.Insertable(model).ExecuteReturnSnowflakeIdAsync();

    /// <summary>
    /// 保存集合（返回雪花id）
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<List<long>> SaveAllBySnowflakeIdAsync(List<TEntity> models) => await Client.Insertable(models).ExecuteReturnSnowflakeIdListAsync();

    /// <summary>
    /// 保存集合
    /// </summary>
    /// <param name="input">输入值</param>
    /// <returns></returns>
    public async Task<int> SaveAllAsync(List<TEntity> models) => await Client.Insertable(models).ExecuteCommandAsync();

    /// <summary>
    /// 修改单个
    /// </summary>
    /// <param name="model">输入值</param>
    /// <returns></returns>
    public async Task<int> UpdateAsync(TEntity model) => await Client.Updateable(model).ExecuteCommandAsync();

    /// <summary>
    /// 修改单个(添加条件)
    /// </summary>
    /// <param name="model">输入值</param>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<int> UpdateAsync(TEntity model, Expression<Func<TEntity, bool>> expression) => await Client.Updateable(model).Where(expression).ExecuteCommandAsync();

    /// <summary>
    /// 修改集合
    /// </summary>
    /// <param name="models">输入集合</param>
    /// <returns></returns>
    public async Task<int> UpdateAllAsync(List<TEntity> models) => await Client.Updateable(models).ExecuteCommandAsync();

    /// <summary>
    /// 修改集合(添加条件)
    /// </summary>
    /// <param name="models">输入集合</param>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<int> UpdateAllAsync(List<TEntity> models, Expression<Func<TEntity, bool>> expression) => await Client.Updateable(models).Where(expression).ExecuteCommandAsync();

    /// <summary>
    /// 插入或更新集合
    /// </summary>
    /// <param name="models">输入值</param>
    /// <returns></returns>
    public async Task<int> SaveOrUpdateAllAsync(List<TEntity> models) => await Client.Storageable(models).ExecuteCommandAsync();

    /// <summary>
    /// 根据主键删除
    /// </summary>
    /// <param name="id">主键id</param>
    /// <returns></returns>
    public async Task<int> DeleteAsync(object id) => await Deleteable().In(id).ExecuteCommandAsync();

    /// <summary>
    /// 根据主键删除多个
    /// </summary>
    /// <param name="ids">id字符串，以逗号隔开</param>
    /// <returns></returns>
    public async Task<int> DeleteByIdsAsync(int[] ids) => await Deleteable().In(ids).ExecuteCommandAsync();

    /// <summary>
    /// 根据表达式删除
    /// </summary>
    /// <param name="expression">表达式</param>
    /// <returns></returns>
    public async Task<int> DeleteAsync(Expression<Func<TEntity, bool>> expression) => await Deleteable().Where(expression).ExecuteCommandAsync();

    #endregion 基本操作方法

    #region sql语句操作方法

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public async Task<TEntity> GetSingleBySqlAsync(string sql) => await Client.Ado.SqlQuerySingleAsync<TEntity>(sql);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public async Task<TEntity> GetSingleBySqlAsync(string sql, SugarParameter[] parameters) => await Client.Ado.SqlQuerySingleAsync<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public async Task<TEntity> GetSingleBySqlAsync(string sql, List<SugarParameter> parameters) => await Client.Ado.SqlQuerySingleAsync<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListBySqlAsync(string sql) => await Client.Ado.SqlQueryAsync<TEntity>(sql);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListBySqlAsync(string sql, SugarParameter[] parameters) => await Client.Ado.SqlQueryAsync<TEntity>(sql, parameters);

    /// <summary>
    /// sql语句查询单个
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListBySqlAsync(string sql, List<SugarParameter> parameters) => await Client.Ado.SqlQueryAsync<TEntity>(sql, parameters);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public async Task<int> ExecuteCommandAsync(string sql) => await Client.Ado.ExecuteCommandAsync(sql);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">单个参数</param>
    /// <returns></returns>
    public async Task<int> ExecuteCommandAsync(string sql, SugarParameter[] parameters) => await Client.Ado.ExecuteCommandAsync(sql, parameters);

    /// <summary>
    /// 增删改
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <param name="parameters">多个参数</param>
    /// <returns></returns>
    public async Task<int> ExecuteCommandAsync(string sql, List<SugarParameter> parameters) => await Client.Ado.ExecuteCommandAsync(sql, parameters);

    /// <summary>
    /// 查询字符串
    /// </summary>
    /// <param name="sql">sql语句</param>
    /// <returns></returns>
    public async Task<string> GetStringBySqlAsync(string sql) => await Client.Ado.GetStringAsync(sql);

    #endregion sql语句操作方法

    #endregion 异步操作方法
}